home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Internet PMSAM source / pop.protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-07  |  12.2 KB  |  556 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------
  2.  
  3. AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
  4. Mail Service Access Module
  5.  
  6. written by Steve Falkenburg-- MacDTS
  7. ©1991-1993 Apple Computer, Inc.
  8.  
  9. --------------
  10. change history
  11. --------------
  12.  
  13. SJF        02/19/93    update for beta build    b1
  14. SJF        10/29/92    update to a11            a11
  15. SJF        06/08/92    update to a8            a8
  16. SJF        02/15/92    first working version    a4.5
  17. SJF        10/16/91    initial coding            a3
  18.  
  19. ---------------------------------------------------------------------*/
  20.  
  21. #ifndef __TYPES__
  22. #include <Types.h>
  23. #endif
  24.  
  25. #ifndef __PACKAGES__
  26. #include <Packages.h>
  27. #endif
  28.  
  29. #include <string.h>
  30.  
  31. #ifdef applec
  32. #include <strings.h>
  33. #endif
  34.  
  35. #include "const.h"
  36. #include "gwerrors.h"
  37. #include "mytypes.h"
  38. #include "globals.h"
  39. #include "utils.h"
  40. #include "network.h"
  41. #include "pop.types.h"
  42. #include "pop.constants.h"
  43. #include "parser.h"
  44. #include "spoolsystem.h"
  45.  
  46. #include "pop.protocol.h"
  47.  
  48. OSErr POP_InitiateConnection(unsigned long popAddress,unsigned short popPort,char *user,char *password,unsigned long *connID)
  49. {
  50.     OSErr err;
  51.     Ptr response;
  52.     unsigned long responseLength;
  53.     char command[256];
  54.     GetCRLFStates state;
  55.     
  56.     TCP_FlushBytes();
  57.     
  58.     err = TCP_CreateStream(connID);
  59.     if (err!=noErr) {
  60.         return err;
  61.     }
  62.  
  63.     err = TCP_ActiveOpen(*connID,popAddress,popPort,kPOPTimeout);
  64.     if (err!=noErr) {
  65.         TCP_ReleaseStream(*connID);
  66.         return kInvalidPopServer;
  67.     }
  68.     
  69.     state = sCRLFNormal;
  70.     POP_GetTextToCRLF(*connID,&response,&responseLength,&state);
  71.     if (response)
  72.         DisposPtrChk(response);
  73.         
  74.     strcpy(command,"USER ");
  75.     strcat(command,user);
  76.     err = POP_Command(*connID,command,&response,&responseLength);
  77.     if (err!=noErr) {
  78.         POP_CloseConnection(*connID);
  79.         if (err==kPOPError)
  80.             err = kInvalidUsername;
  81.         return err;
  82.     }
  83.     DisposPtrChk(response);
  84.     
  85.     strcpy(command,"PASS ");
  86.     strcat(command,password);
  87.     err = POP_Command(*connID,command,&response,&responseLength);
  88.     if (err!=noErr) {
  89.         POP_CloseConnection(*connID);
  90.         if (err==kPOPError)
  91.             err = kInvalidPasssword;
  92.         return err;
  93.     }
  94.     DisposPtrChk(response);
  95.     
  96.     return err;
  97. }
  98.  
  99.  
  100. OSErr POP_GetDropStats(unsigned long connID,short *numMessages,long *messageSize)
  101. {
  102.     char command[256];
  103.     char *word,*responsePtr;
  104.     Ptr response;
  105.     unsigned long responseLength;
  106.     long number;
  107.     OSErr err;
  108.     
  109.     strcpy(command,"STAT");
  110.     err = POP_Command(connID,command,&response,&responseLength);
  111.     if (err!=noErr) {
  112.         return err;
  113.     }
  114.     
  115.     /* get drop text */
  116.     
  117.     responsePtr = (char *)response;
  118.     GetWord(&word,&responsePtr);            // get rid of +OK / -ERR
  119.     GetNumber(&number,&responsePtr);        // get number of messages
  120.     *numMessages = (short) number;
  121.     GetNumber(&number,&responsePtr);        // get size of mailbox in bytes
  122.     *messageSize = number;
  123.     
  124.     DisposPtrChk(response);
  125.     return err;
  126. }
  127.  
  128.  
  129. OSErr POP_GetMessageIDs(unsigned long connID,TMsgIDList *messageIDList,short *numMessageIDs)
  130. {
  131.     char command[256];
  132.     Ptr response;
  133.     unsigned long responseLength;
  134.     char *responsePtr;
  135.     long number;
  136.     short numMsgs,msgIndex;
  137.     OSErr err;
  138.     GetTermStates state;
  139.     
  140.     strcpy(command,"LIST");
  141.     err = POP_Command(connID,command,&response,&responseLength);
  142.     if (err!=noErr) {
  143.         return err;
  144.     }
  145.     DisposPtrChk(response);
  146.     
  147.     state = sGotLF;
  148.     err = POP_GetTextToTerminator(connID,&response,&responseLength,&state);
  149.     if (err!=noErr) {
  150.         return err;
  151.     }
  152.  
  153.     if (responseLength==0) {
  154.         *numMessageIDs = 0;
  155.         return err;
  156.     }
  157.         
  158.     responsePtr = (char *)response;
  159.     numMsgs = *numMessageIDs = CountLines(responsePtr);
  160.     if (numMsgs > 0) {
  161.     
  162.         *messageIDList = (TMsgIDList)NewPtrChk(sizeof(TMsgID)*numMsgs);
  163.         if ((err=MemError())!=noErr) {
  164.             DisposPtrChk(response);
  165.             return err;
  166.         }
  167.         
  168.         msgIndex = 0;
  169.         while (*responsePtr) {
  170.             GetNumber(&number,&responsePtr);    // get message ID
  171.             (*messageIDList)[msgIndex] = (TMsgID)number;
  172.             GetNumber(&number,&responsePtr);    // get message size & discard in this version
  173.             msgIndex++;
  174.         }
  175.         
  176.     }
  177.     DisposPtrChk(response);
  178.     return err;
  179. }
  180.  
  181.  
  182. OSErr POP_GetMessage(unsigned long connID,TMsgID messageID,Ptr *header,FSSpec *spoolSpec)
  183. {
  184.     char command[256],messageIDStr[256];
  185.     Ptr response,bodyResponse;
  186.     unsigned long responseLength;
  187.     OSErr err;
  188.     GetCRLFCRLFStates crlfcrlfState;
  189.     GetCRLFStates crlfState;
  190.     Boolean first;
  191.     
  192.     strcpy(command,"RETR ");
  193.     MessageIDToString(messageID,messageIDStr);
  194.     strcat(command,messageIDStr);
  195.     err = POP_Command(connID,command,&response,&responseLength);
  196.     if (err!=noErr) {
  197.         return err;
  198.     }
  199.     DisposPtrChk(response);
  200.     
  201.     // get message header (into a memory buffer)
  202.     
  203.     crlfcrlfState = sCRLFCRLFNormal;
  204.     err = POP_GetTextToCRLFCRLF(connID,&response,&responseLength,&crlfcrlfState);
  205.     if (err!=noErr) {
  206.         return err;
  207.     }
  208.  
  209.     if (responseLength==0)
  210.         return kErrResponse;
  211.     StripLF((char *)response,&responseLength);
  212.     *header = response;
  213.  
  214.     // get message body (into a disk file)
  215.     
  216.     crlfState = sGotLF;
  217.     first = true;
  218.     do {
  219.         err = POP_GetTextToTerminator(connID,&bodyResponse,&responseLength,&crlfState);
  220.         if (err!=noErr)
  221.             return err;
  222.         StripLF((char *)bodyResponse,&responseLength);
  223.         if (first) {
  224.             SpoolToFile(spoolSpec,kRawContentType,kRawContentCreator,0,bodyResponse,responseLength);
  225.             first = false;
  226.         }
  227.         else
  228.             AppendToSpool(spoolSpec,kRawContentType,kRawContentCreator,0,bodyResponse,responseLength);
  229.         DisposPtrChk(bodyResponse);
  230.      } while (crlfState!=sFinished);
  231.      
  232.     return err;
  233. }
  234.  
  235.  
  236. OSErr POP_DeleteMessage(unsigned long connID,TMsgID messageID)
  237. {
  238.     char command[256],messageIDStr[256];
  239.     Ptr response;
  240.     unsigned long responseLength;
  241.     OSErr err;
  242.     
  243.     strcpy(command,"DELE ");
  244.     MessageIDToString(messageID,messageIDStr);
  245.     strcat(command,messageIDStr);
  246.     err = POP_Command(connID,command,&response,&responseLength);
  247.     if (err!=noErr) {
  248.         return err;
  249.     }
  250.     DisposPtrChk(response);
  251.     return err;
  252. }
  253.  
  254.  
  255. OSErr POP_CloseConnection(unsigned long connID)
  256. {
  257.     char command[256];
  258.     Ptr response;
  259.     unsigned long responseLength;
  260.     OSErr err;
  261.     
  262.     strcpy(command,"QUIT");
  263.     err = POP_Command(connID,command,&response,&responseLength);
  264.     if (err==noErr) {
  265.         DisposPtrChk(response);
  266.     }
  267.     
  268.     err = TCP_CloseConnection(connID,kPOPTimeout);
  269.     err = TCP_ReleaseStream(connID);
  270.     
  271.     TCP_FlushBytes();
  272.     
  273.     return err;
  274. }
  275.  
  276.  
  277. OSErr POP_Command(unsigned long connID,char *command,Ptr *response,unsigned long *responseLength)
  278. {
  279.     char sendCommand[256];
  280.     unsigned short sendLength;
  281.     OSErr err;
  282.     GetCRLFStates state;
  283.     
  284.     strcpy(sendCommand,command);
  285.     strcat(sendCommand,kCRLF);
  286.     sendLength = strlen(sendCommand);
  287.     
  288.     err = TCP_Send(connID,sendCommand,sendLength,true,kPOPTimeout);
  289.     if (err!=noErr)
  290.         return err;
  291.     
  292.     state = sCRLFNormal;
  293.     err = POP_GetTextToCRLF(connID,response,responseLength,&state);
  294.     if (err!=noErr)
  295.         return err;
  296.     
  297.     if (*responseLength>0 && (*response)[0]=='-') {
  298.         DisposPtrChk(*response);
  299.         return kPOPError;
  300.     }
  301.     
  302.     return noErr;
  303. }
  304.  
  305.  
  306. OSErr POP_GetTextToTerminator(unsigned long connID,Ptr *response,unsigned long *responseLength,GetTermStates *savedState)
  307. {
  308.     OSErr err;
  309.     unsigned long receivedBytes;
  310.     Handle dataHandle;
  311.     Ptr dataPtr;
  312.     unsigned long handleSize;
  313.     unsigned char dataByte;
  314.     GetTermStates stateMachine;
  315.     
  316.     stateMachine = *savedState;    // NOTE: normally, we start at sGotLF
  317.     
  318.     receivedBytes = 0;
  319.     handleSize = kTransactionBite;
  320.     dataHandle = NewHandleChk(handleSize);
  321.     if (MemError()!=noErr)
  322.         return MemError();
  323.     MoveHHi(dataHandle);
  324.     HLock(dataHandle);
  325.     dataPtr = *dataHandle;
  326.         
  327.     do {
  328.         err = TCP_ReadByte(connID,&dataByte,kPOPTimeout);
  329.         if (err==noErr) {
  330.         
  331.             /* store data */
  332.             
  333.             dataPtr[receivedBytes++] = dataByte;
  334.             
  335.             /* advance state machine */
  336.             
  337.             if (dataByte==CR) {
  338.                 if (stateMachine==sNormal || stateMachine==sGotTerminator)
  339.                     stateMachine++;
  340.                 else
  341.                     stateMachine==sNormal;
  342.             }
  343.             else if (dataByte==LF) {
  344.                 if (stateMachine==sGotCR || stateMachine==sGotPostTermCR)
  345.                     stateMachine++;
  346.                 else
  347.                     stateMachine==sNormal;
  348.             }
  349.             else if (dataByte==kMessageTerminator) {
  350.                 if (stateMachine==sGotLF)
  351.                     stateMachine++;
  352.                 else
  353.                     stateMachine==sNormal;
  354.             }
  355.             else
  356.                 stateMachine = sNormal;
  357.             
  358.             if (receivedBytes==handleSize) {
  359.                 handleSize += kTransactionBite;
  360.                 HUnlock(dataHandle);
  361.                 SetHandleSize(dataHandle,handleSize);
  362.                 err = MemError();
  363.                 MoveHHi(dataHandle);
  364.                 HLock(dataHandle);
  365.                 dataPtr = *dataHandle;
  366.             }
  367.         }
  368.     } while (err==noErr && handleSize <= kMaxPOPTransactionSize && stateMachine!=sFinished);
  369.     
  370.     if (stateMachine==sFinished)
  371.         receivedBytes -= 3;
  372.         
  373.     *responseLength = receivedBytes;
  374.  
  375.     if (receivedBytes!=0) {
  376.         *response = NewPtrChk(receivedBytes+1);
  377.         if (MemError()!=noErr)
  378.             return MemError();
  379.         BlockMove(dataPtr,*response,receivedBytes);
  380.         (*response)[receivedBytes++] = '\0';        // null terminate response
  381.     }
  382.     
  383.     DisposHandleChk(dataHandle);
  384.     *savedState = stateMachine;
  385.     
  386.     return err;
  387. }
  388.  
  389.  
  390. OSErr POP_GetTextToCRLF(unsigned long connID,Ptr *response,unsigned long *responseLength,GetCRLFStates *savedState)
  391. {
  392.     OSErr err;
  393.     unsigned long receivedBytes;
  394.     Handle dataHandle;
  395.     Ptr dataPtr;
  396.     unsigned long handleSize;
  397.     unsigned char dataByte;
  398.     GetCRLFStates stateMachine;
  399.     
  400.     stateMachine = *savedState;
  401.     
  402.     receivedBytes = 0;
  403.     handleSize = kTransactionBite;
  404.     dataHandle = NewHandleChk(handleSize);
  405.     if (MemError()!=noErr)
  406.         return MemError();
  407.     MoveHHi(dataHandle);
  408.     HLock(dataHandle);
  409.     dataPtr = *dataHandle;
  410.         
  411.     do {
  412.         err = TCP_ReadByte(connID,&dataByte,kPOPTimeout);
  413.         if (err==noErr) {
  414.         
  415.             /* store data */
  416.             
  417.             dataPtr[receivedBytes++] = dataByte;
  418.             
  419.             /* advance state machine */
  420.             
  421.             if (dataByte==CR) {
  422.                 if (stateMachine==sCRLFNormal)
  423.                     stateMachine++;
  424.                 else
  425.                     stateMachine==sCRLFNormal;
  426.             }
  427.             else if (dataByte==LF) {
  428.                 if (stateMachine==sCRLFGotCR)
  429.                     stateMachine++;
  430.                 else
  431.                     stateMachine==sCRLFNormal;
  432.             }
  433.             else
  434.                 stateMachine = sCRLFNormal;
  435.             
  436.             if (receivedBytes==handleSize) {
  437.                 handleSize += kTransactionBite;
  438.                 HUnlock(dataHandle);
  439.                 SetHandleSize(dataHandle,handleSize);
  440.                 err = MemError();
  441.                 MoveHHi(dataHandle);
  442.                 HLock(dataHandle);
  443.                 dataPtr = *dataHandle;
  444.             }
  445.         }
  446.     } while (err==noErr && handleSize <= kMaxPOPTransactionSize && stateMachine!=sCRLFFinished);
  447.     
  448.     if (stateMachine==sCRLFFinished)
  449.         receivedBytes -= 2;
  450.     
  451.     *responseLength = receivedBytes;
  452.     
  453.     if (receivedBytes!=0) {
  454.         *response = NewPtrChk(receivedBytes+1);
  455.         if ((err = MemError())!=noErr) {
  456.             DisposHandleChk(dataHandle);
  457.             return err;
  458.         }
  459.         BlockMove(dataPtr,*response,receivedBytes);
  460.         (*response)[receivedBytes++] = '\0';        // null terminate response
  461.         DisposHandleChk(dataHandle);
  462.     }
  463.     
  464.     *savedState = stateMachine;
  465.     return err;
  466. }
  467.  
  468.  
  469. OSErr POP_GetTextToCRLFCRLF(unsigned long connID,Ptr *response,unsigned long *responseLength,GetCRLFCRLFStates *savedState)
  470. {
  471.     OSErr err;
  472.     unsigned long receivedBytes;
  473.     Handle dataHandle;
  474.     Ptr dataPtr;
  475.     unsigned long handleSize;
  476.     unsigned char dataByte;
  477.     GetCRLFCRLFStates stateMachine;
  478.     
  479.     stateMachine = *savedState;
  480.     
  481.     receivedBytes = 0;
  482.     handleSize = kTransactionBite;
  483.     dataHandle = NewHandleChk(handleSize);
  484.     if (MemError()!=noErr)
  485.         return MemError();
  486.     MoveHHi(dataHandle);
  487.     HLock(dataHandle);
  488.     dataPtr = *dataHandle;
  489.         
  490.     do {
  491.         err = TCP_ReadByte(connID,&dataByte,kPOPTimeout);
  492.         if (err==noErr) {
  493.         
  494.             /* store data */
  495.             
  496.             dataPtr[receivedBytes++] = dataByte;
  497.             
  498.             /* advance state machine */
  499.             
  500.             if (dataByte==CR) {
  501.                 if ((stateMachine==sCRLFCRLFNormal) || (stateMachine==sCRLFCRLFGotLF))
  502.                     stateMachine++;
  503.                 else
  504.                     stateMachine==sCRLFCRLFNormal;
  505.             }
  506.             else if (dataByte==LF) {
  507.                 if ((stateMachine==sCRLFCRLFGotCR) || (stateMachine==sCRLFCRLFGetPostCR))
  508.                     stateMachine++;
  509.                 else
  510.                     stateMachine==sCRLFCRLFNormal;
  511.             }
  512.             else
  513.                 stateMachine = sCRLFCRLFNormal;
  514.             
  515.             if (receivedBytes==handleSize) {
  516.                 handleSize += kTransactionBite;
  517.                 HUnlock(dataHandle);
  518.                 SetHandleSize(dataHandle,handleSize);
  519.                 err = MemError();
  520.                 MoveHHi(dataHandle);
  521.                 HLock(dataHandle);
  522.                 dataPtr = *dataHandle;
  523.             }
  524.         }
  525.     } while (err==noErr && handleSize <= kMaxPOPTransactionSize && stateMachine!=sCRLFCRLFFinished);
  526.     
  527.     if (stateMachine==sCRLFCRLFFinished)
  528.         receivedBytes -= 4;
  529.     
  530.     *responseLength = receivedBytes;
  531.     
  532.     if (receivedBytes!=0) {
  533.         *response = NewPtrChk(receivedBytes+1);
  534.         if ((err = MemError())!=noErr) {
  535.             DisposHandleChk(dataHandle);
  536.             return err;
  537.         }
  538.         BlockMove(dataPtr,*response,receivedBytes);
  539.         (*response)[receivedBytes++] = '\0';        // null terminate response
  540.         DisposHandleChk(dataHandle);
  541.     }
  542.     
  543.     *savedState = stateMachine;
  544.     return err;
  545. }
  546.  
  547.  
  548. void MessageIDToString(TMsgID messageID,char *messageIDStr)
  549. {
  550.     long msgIDLong;
  551.     
  552.     msgIDLong = (long) messageID;
  553.     NumToString(msgIDLong,(StringPtr)messageIDStr);
  554.     p2cstr((StringPtr)messageIDStr);
  555. }
  556.